﻿using System.Collections.Concurrent;
using System.Threading;
using static SimpleTerminal.PaintMessage.Message;

namespace SimpleTerminal.PaintMessage
{
    public abstract class PaintHandler
    {
        private readonly ConcurrentQueue<Message> paintMessages = new ConcurrentQueue<Message>();
        private static readonly ConcurrentQueue<Message> messagesPool = new ConcurrentQueue<Message>();
        public readonly AutoResetEvent _wait = new AutoResetEvent(false);
        private readonly AutoResetEvent _waitEmpty = new AutoResetEvent(false);

        /// <summary>
        /// 循环处理消息队列
        /// </summary>
        public void Loop()
        {
            while (_wait.WaitOne())
            {
                while (paintMessages.TryDequeue(out Message message))
                {
                    HandleMessage(message);
                }
                _waitEmpty.Set();
            }
        }

        public void WaitEmpty()
        {
            if (paintMessages.Count > 0)
                _waitEmpty.WaitOne();
        }

        /// <summary>
        /// 处理过程，需要用户集成复写
        /// </summary>
        /// <param name="paintMessage"></param>
        protected abstract void HandleMessage(Message paintMessage);

        /// <summary>
        /// 发送一个消息到消息队列中，并唤醒消息队列
        /// </summary>
        /// <param name="paintMessage"></param>
        public void SendMessage(Message paintMessage)
        {
            paintMessages.Enqueue(paintMessage);
            _wait.Set();
        }

        public void ClearMessages()
        {
            //删除队列消息
            while (paintMessages.TryDequeue(out Message message))
                ReleaseMessage(message);
        }

        /// <summary>
        /// 从缓冲池中取出一个消息对象
        /// 如果不存在则新建
        /// </summary>
        /// <returns></returns>
        public static Message ObtainMessage()
        {
            return ObtainMessage(TEvent.Paint);
        }

        /// <summary>
        /// 从缓冲池中取出一个消息对象
        /// 如果不存在则新建
        /// </summary>
        /// <returns></returns>
        public static Message ObtainMessage(TEvent What)
        {
            return ObtainMessage(What, -1, -1);
        }

        /// <summary>
        /// 从缓冲池中取出一个消息对象
        /// 如果不存在则新建
        /// </summary>
        /// <returns></returns>
        public static Message ObtainMessage(TEvent What, int arg1, int arg2)
        {
            if (messagesPool.TryDequeue(out Message message))
            {
                message.What = What;
                message.arg1 = arg1;
                message.arg2 = arg2;
                message.arg3 = -1;
                message.arg4 = -1;
                message._wait.Reset();
                return message;
            }
            return new Message(What, arg1, arg2, -1, -1);
        }


        /// <summary>
        /// 将消息标记为释放并且放入缓冲池
        /// 请仅对ObtainMessage获取的消息进行此操作
        /// 否则会导致缓冲池越来越大
        /// </summary>
        /// <param name="message"></param>
        public static void ReleaseMessage(Message message)
        {
            message.Release();
            messagesPool.Enqueue(message);
        }

    }
}
